#include "fml_pwr_control.h"
#include "hal_modbus_uart.h"

typedef enum
{
    STAT_SEND_REQ = 0,
    STAT_WAIT_RESP,
}MODBUS_STAT;

static uint32_t s_timestamp = 0;

static void print_hex(void *addr, uint32_t len)
{
    int j = 0;
    
    for (j = 0; j < len; j++)
    {
        if ((j % 32 == 0) && j)
        {
            printf("\r\n");
        }
        printf("%02X ", ((uint8_t *)addr)[j]);
    }
    printf("\r\n");
}

void fml_pwr_control_init(void)
{
    s_timestamp = HAL_GetTick();
    hal_relay_gpio_init();
    hal_modbus_uart_init();
}

int32_t fml_modbus_send(uint8_t *data, uint32_t data_len)
{   
    return hal_modbus_uart_write(data, data_len);
}

int32_t fml_modbus_recv(uint8_t *buff, uint32_t buff_len)
{
    return hal_modbus_uart_read(buff, buff_len);
}


#define Read_ID 1

uint32_t Voltage_data, Current_data, Power_data, Energy_data, Pf_data, CO2_data;

uint16_t calc_crc(uint8_t crcbuf, uint16_t crc) 
{ 
    uint32_t i;
    uint8_t chk;
    
    crc = crc ^ crcbuf;
    
    for(i = 0; i < 8; i++) 
    { 
        chk = (uint8_t)(crc&1);
        crc = crc >> 1;
        crc = crc & 0x7fff;
        if (chk == 1)
            crc = crc ^ 0xa001;
        crc = crc & 0xffff;
    }
    
    return crc; 
}

uint16_t check_crc(unsigned char *buf, unsigned char len)
{
    unsigned char hi,lo;
    uint32_t i;
    unsigned int crc;
    crc = 0xFFFF;

    for(i = 0; i < len; i++)
    { 
        crc=calc_crc(*buf, crc);
        buf++;
    }

    hi=( unsigned char)(crc%256);
    lo=( unsigned char)(crc/256);
    crc=(((unsigned int)(hi))<<8) | lo;

    return crc; 
}

void read_data(void)
{
    union crcdata
    { 
        uint16_t word16;
        uint8_t byte[2];
    }crcnow;
    
    uint8_t tx_buff[8];
    
    tx_buff[0] = Read_ID;
    tx_buff[1] = 0x03;
    tx_buff[2] = 0x00;
    tx_buff[3] = 0x48;
    tx_buff[4] = 0x00;
    tx_buff[5] = 0x06;
    crcnow.word16 = check_crc(tx_buff, 6);
    tx_buff[6] = crcnow.byte[1];
    tx_buff[7] = crcnow.byte[0];

    printf("MODBUS-->: %d byte\n", sizeof(tx_buff));
    print_hex(tx_buff, sizeof(tx_buff));
    fml_modbus_send(tx_buff, sizeof(tx_buff));
}

void analysis_data(uint8_t *data, uint32_t len)
{ 
    uint8_t i;
    union crcdata
    { 
        uint16_t word16;
        uint8_t byte[2];
    }crcnow; 
    
    if(data[0] == Read_ID) //确认 ID 正确
    { 
        crcnow.word16 = check_crc(data, len - 2);                                   //reveive_numbe 是接收数据总长度
        if((crcnow.byte[0] == data[len - 1]) && (crcnow.byte[1] == data[len - 2]))    //确认 CRC 校验正确
        {   
            Voltage_data=(((uint32_t)(data[3]))<<24)|(((uint32_t)(data[4]))<<16)|(((uint32_t)(data[5]))<<8)|data[6];
            Current_data=(((uint32_t)(data[7]))<<24)|(((uint32_t)(data[8]))<<16)|(((uint32_t)(data[9]))<<8)|data[10];
            Power_data=(((uint32_t)(data[11]))<<24)|(((uint32_t)(data[12]))<<16)|(((uint32_t)(data[13]))<<8)|data[14];
            Energy_data=(((uint32_t)(data[15]))<<24)|(((uint32_t)(data[16]))<<16)|(((uint32_t)(data[17]))<<8)|data[18];
            Pf_data=(((uint32_t)(data[19]))<<24)|(((uint32_t)(data[20]))<<16)|(((uint32_t)(data[21]))<<8)|data[22];
            CO2_data=(((uint32_t)(data[23]))<<24)|(((uint32_t)(data[24]))<<16)|(((uint32_t)(data[25]))<<8)|data[26]; 

            printf("Voltage: %d\nCurrent: %d\nPowerEnergy: %d\n", Voltage_data, Current_data, Power_data);
        }
    }
}

extern void print_hex(void *addr, uint32_t len);
extern void dump_hex(void *addr, uint32_t len);

void fml_modbus_comm(void)
{
    static MODBUS_STAT s_modbus_stat = STAT_SEND_REQ;

    switch (s_modbus_stat)
    {
        case STAT_SEND_REQ:
        {
            read_data();
            s_timestamp = HAL_GetTick();
            s_modbus_stat = STAT_WAIT_RESP;
            break;
        }
        case STAT_WAIT_RESP:
        {
            uint8_t buff[50] = {0};
            uint32_t timestamp = HAL_GetTick();
            int32_t recv_len = 0;
            if(timestamp - s_timestamp > 1000)
            {
                memset(buff, 0, sizeof(buff));
                recv_len = fml_modbus_recv(buff, sizeof(buff));
                if (recv_len > 0)
                {
                    print_hex(buff, recv_len);
                    analysis_data(buff, recv_len);
                }
                s_timestamp = timestamp;
                s_modbus_stat = STAT_SEND_REQ;
            }
            break;
        }
        default:
        {
            s_modbus_stat = STAT_SEND_REQ;
        }
    }
}



